Skip to content

fix(server): omit content for 205 responses - #4262

Open
akasakariko wants to merge 2 commits into
hyperium:masterfrom
akasakariko:fix-205-no-content
Open

akasakariko wants to merge 2 commits into
hyperium:masterfrom
akasakariko:fix-205-no-content

Conversation

@akasakariko

@akasakariko akasakariko commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

A 205 response must not contain content (RFC 9110 Section 15.3.6), but the server still sent a body and a non-zero Content-Length

  • HTTP/1 now drops the body and sends Content-Length: 0, keeping the response correctly framed
  • HTTP/2 now drops the body and removes Content-Length for 205 responses
  • HTTP/2 no longer sends body data for responses to HEAD requests
  • HTTP/2 no longer sends Content-Length for 204 responses (RFC 9113 Section 8.1)
  • HTTP/2 checks 204, 205, and 304 status restrictions before HEAD framing, so HEAD requests for 204 and 205 responses also have no Content-Length

The HTTP/1 behavior matches the existing handling for empty 205 responses, which already sent Content-Length: 0

Tests were added in tests/server.rs for HTTP/1 205 responses and HTTP/2 204, 205, HEAD, and HEAD 204/205 responses

Verification:

  • cargo test --features full: 333 passed, 10 ignored

  • cargo clippy --features full -- -D warnings: exits 0

  • rustfmt --check --edition 2021 $(git ls-files '*.rs'): passes

  • cargo hack --no-dev-deps check --feature-powerset --depth 2 --skip ffi,tracing with -D dead_code -D unused_imports: passes

  • Same feature-powerset check with tracing and --cfg hyper_unstable_tracing: passes

  • The description, docs, and comments (words meant for humans) are written by a human, not by an LLM.

A 205 response must not contain content (RFC 9110 Section 15.3.6).
The HTTP/1 server now drops the body and sends `Content-Length: 0` so
the response stays correctly framed. The HTTP/2 server drops the body
and removes `Content-Length`.

The HTTP/2 server also stops sending body data for responses to HEAD
requests and removes `Content-Length` from 204 responses, as required
by RFC 9110 Section 6.4.1 and RFC 9113 Section 8.1.

Closes hyperium#4261

@agammann agammann left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The HTTP/2 branch handles HEAD before the 204/205 status case. For a HEAD request whose service returns 204 No Content with a body that has an exact size hint, is_head sets a nonzero Content-Length and the else if that removes that header is skipped. The new GET 204 test and HEAD 200 test do not cover their intersection. Could the status restriction take precedence for 204/205, with a HEAD 204 (and ideally 205) regression? I reviewed the diff and surrounding framing code; I did not run tests locally.

204, 205, and 304 responses never contain content, so handle the status before the HEAD branch instead of after it, and remove Content-Length for 204 and 205 regardless of the request method

Adds a regression covering HEAD requests with 204 and 205 responses
@akasakariko

Copy link
Copy Markdown
Contributor Author

Addressed in the latest commit: the HTTP/2 server now checks 204, 205, and 304 status restrictions before HEAD framing and removes Content-Length for 204 and 205 regardless of the request method

The new regression in tests/server.rs covers HEAD requests with 204 and 205 responses, including a body with an exact size hint

Local verification: the targeted regression, cargo test --features full, cargo clippy --features full -- -D warnings, rustfmt check, and both feature-powerset checks pass

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants